#ifndef INPAINTINGTHESE_H
#define INPAINTINGTHESE_H
/**
 * \file InpaintingThese.h
 * \brief Renferme tous les secrets de l'inpainting de la thèse !
 * \author Quentin Grimaud
 *
 */
//#include <GL/glut.h>
#include <math.h> // exp ()
#include <algorithm> // max (), min ()
#include <iostream> // cout
#include <strings.h> // bzero ()
#include <sys/time.h> // gettimeofday ()
#include <cstdlib> // srand (), rand ()
//#include <ctime> // time ()
#include <algorithm> // min (), max ()

#include "Matrice.h"
#include "vecteur.h"
#include "Pixel.h"
#include "Masque.h"
#include "Image.h"

#ifndef PI
#define PI 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
#endif

/*! \class InpaintingThese
* \brief Classe d'inpainting de la thèse
*
*  La classe permet l'application de la méthode de l'inpainting de la thèse
*/

class QDessinGL;

class InpaintingThese
{
public:
/*!
 *  \brief Constructeur
 *
 *  Constructeur de la classe InpaintingThese
 *
 *  \param _src : l'image à inpainter
 *  \param _msk : le masque à utiliser sur l'image
 *  \param _dest : l'image résultante de l'inpainting
 *  \param _sigma : variance de la gaussienne
 *  \param _tailleVoisinage : le côté de la fenêtre de voisinnage à utiliser pour la gaussienne
 */
	InpaintingThese ( Image * _src = NULL, int canaux = 0, Masque * _msk = NULL,
		Image * _dest = NULL, double _sigma = 1.0, int _tailleVoisinage = 20,QDessinGL* parent=NULL );
/*!
 *  \brief Destructeur
 *
 *  Destructeur de la classe InpaintingThese
 */
	~InpaintingThese();


/*!
 *  \brief renvoie la valeur de la Gaussienne au point de voisinage considéré
 *
 *  Gaussienne 2D normalisée de centre (0;0) et de variance sigma (en x comme en y).
 *
 *  \param _x : abscisse du point dont on veut la Gaussienne
 *  \param _y : ordonnée du point dont on veut la Gaussienne
 *  \param _sigma : variance de la Gaussienne
 *  \return z, la valeur de la Gaussienne au point (x;y)
 */
	double Gaussienne ( int _x, int _y, double _sigma = 0.0 /* trick */ );
	
/*!
 *  \brief calcule la matrice Hessienne 2x2 pour le canal i du pixel (x;y)
 *
 *  Matrice Hessienne, cf définition "3.5.2 Using a spatial discretization of the Hessian", P103 de la thèse.
 *
 *  \param _x : abscisse du pixel
 *  \param _y : ordonnée du pixel
 *  \param _i : canal de couleur (0,1,2)
 *  \param _mat : la matrice à remplir (si NULL, elle sera créée)
 *  \param _img : l'image
 *  \return pointeur vers la matrice calculée
 */	
	Matrice * Hessienne ( int _x, int _y, int _i = 0,
		Matrice * _mat = NULL, Image * _img = NULL );
	
/*!
 *  \brief calcule Ggras
 *
 *  Blah.
 *
 *  \param _x : abscisse du point courant
 *  \param _y : ordonnée du point courant
 *  \param _res : pointeur vers la matrice résultante G (gras) 2x2
 *  \param _sigma : variance de la gaussienne
 *  \param _tailleVoisinage : taille du voisinage à visiter
 *  \return pointeur vers la matrice résultante G (gras) 2x2
 */	
	Matrice * calculGgras ( int _x, int _y, Matrice * _res = NULL,
		double _sigma = 0.0, int _tailleVoisinage = 0 );
	
/*!
 *  \brief calcule la matrice D (gras)
 *
 *  Utilise les 2 valeurs propres et les 2 vecteurs propres pour calculer la matrice 2x2 D (gras).
 *
 *  \param _lambda1 : valeur propre 1
 *  \param _lambda2 : valeur propre 2
 *  \param _theta1 : valeur propre 1 (matrice 1 colonne et 2 lignes)
 *  \param _theta2 : valeur propre 2 (matrice 1 colonne et 2 lignes)
 *  \param _res : la matrice résultat (si NULL, elle sera créée)
 *  \return pointeur vers la matrice 2x2 D (gras)
 */	
	Matrice * calculD ( float _lambda1, float _lambda2,
		Matrice * _theta1, Matrice * _theta2, Matrice * _res );

/*!
 *  \brief tout l'algo
 *
 *	$gnuplot
 *	gnuplot> s = 2.6
 *	gnuplot> splot (1/(2*pi*s*s))*exp(-(x*x+y*y)/(2*s*s))
 *
 *  \return void
 */	
	void tout ( Masque * _msk = NULL, int _canaux = 0,
		int _iterations = 0, Image * _src = NULL, Image * _dest = NULL,
		double _sigma = 0.0/*, int _tailleVoisinage = 0*/ );

/*!
 *  \brief Arrête le traitement en cours
 *
 *  \return void
 */	
	void stop ( void );


private:
	Image * src; /*!<l'image à inpainter*/
	int canaux; /*!<le nombre de canaux de couleur de l'image*/
	Masque * msk; /*!<le masque à utiliser sur l'image*/
	Image * dest; /*!<l'image résultante de l'inpainting*/
	double sigma; /*!<variance de la gaussienne*/
	int tailleVoisinage; /*!<le côté de la fenêtre de voisinnage à utiliser pour la gaussienne*/
	QDessinGL* parent;
	int w;
	int h;
	Matrice ** aGgTTousCanaux; /*!<tableau de pointeurs de matrices 2x2 de ggTtousCanaux
		pour des x allant de 0-tailleVoisinage/2 à (w-1)+tailleVoisinage/2 => fourchette de w+tailleVoisinage
		et des y allant de 0-tailleVoisinage/2 à (h-1)+tailleVoisinage/2  => fourchette de h+tailleVoisinage
		donc le tableau total fait (w+tailleVoisinage)*(h+tailleVoisinage) cases
		quand on cherche la valeur au pixel (x;y), on accède à a[(h+tailleVoisinage)*(y+tV/2)+(x+tV/2)]*/
	int * aGgTTousCanauxOk; /*!<pareil mais des entiers 0 ou 1 pour savoir si la val a déjà été calculée*/
	
	float * aGaussienne; /*!<pareil mais pour le calcul de la Gaussienne
		x va de -tailleVoisinage/2 à tailleVoisinage/2 => fourchette de tailleVoisinage
		x va de -tailleVoisinage/2 à tailleVoisinage/2 => fourchette de tailleVoisinage
		donc le tableau total fait (tailleVoisinage)*(tailleVoisinage) cases
		quand on cherche la valeur en (x;y), on accède à a[(tailleVoisinage)*(y+tV/2)+(x+tV/2)]*/
	int * aGaussienneOk;
	bool bStop;
};

#endif
